package top.honlnk.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.digest.Digester;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.honlnk.common.constant.AutoLoginOptionConstant;
import top.honlnk.common.constant.StaffConstant;
import top.honlnk.common.exception.CustomException;
import top.honlnk.common.network.GetOCRAccessTokenNetwork;
import top.honlnk.common.utils.JWTTokenUtil;
import top.honlnk.common.utils.StringToArrayUtil;
import top.honlnk.mapper.PublicMapper;
import top.honlnk.mapper.ServiceStaffMapper;
import top.honlnk.pojo.dto.ServiceStaffLoginDTO;
import top.honlnk.pojo.dto.ServiceStaffLoginPowerDTO;
import top.honlnk.pojo.entity.OcrAdminInfo;
import top.honlnk.pojo.entity.RotaSecretKey;
import top.honlnk.pojo.entity.SchoolTimetable;
import top.honlnk.pojo.entity.ServiceStaff;
import top.honlnk.pojo.vo.ServiceStaffLoginPowerVO;
import top.honlnk.pojo.vo.StaffGetRotaVO;
import top.honlnk.pojo.vo.ServiceStaffLoginVO;
import top.honlnk.pojo.vo.StaffGetTableVO;
import top.honlnk.service.ServiceStaffService;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Slf4j
@Service
public class ServiceStaffServiceImpl implements ServiceStaffService {

    @Autowired
    private ServiceStaffMapper serviceStaffMapper;

    @Autowired
    private PublicMapper publicMapper;

    @Override
    public ServiceStaffLoginVO login(@NotNull ServiceStaffLoginDTO serviceStaffLoginDTO) {
        String account = serviceStaffLoginDTO.getAccount();
        String password = serviceStaffLoginDTO.getPassword();

        Digester digester = DigestUtil.digester("sm3");
        String passwordSM3 = digester.digestHex(password);

        ServiceStaff serviceStaff = serviceStaffMapper.getStaffByAccount(account);
        if (serviceStaff == null) {
            throw new RuntimeException("账号不存在");
        }
        if (!serviceStaff.getPassword().equals(passwordSM3)) {
            throw new RuntimeException("密码错误");
        }
        int days = switch (serviceStaffLoginDTO.getAutoLoginOption()) {
            case AutoLoginOptionConstant.NOT_AUTO_LOGIN -> 0;
            case AutoLoginOptionConstant.ONE_WEEK -> 7;
            case AutoLoginOptionConstant.ONE_MONTH -> 30;
            case AutoLoginOptionConstant.ONE_YEAR -> 365;
            default -> throw new RuntimeException("自动登录选项无效");
        };
        String token = JWTTokenUtil.genToken(serviceStaff.getId().toString(), serviceStaff.getPassword(), days);
        log.info("Staff生成token: {}", token);
        return ServiceStaffLoginVO.builder()
                .account(account)
                .token(token)
                .mail(serviceStaffMapper.getStaffMailById(serviceStaff.getMailId()))
                .build();
    }

    @Override
    public ServiceStaffLoginPowerVO loginPower(@NotNull ServiceStaffLoginPowerDTO serviceStaffLoginPowerDTO) {
        String account = serviceStaffLoginPowerDTO.getAccount();
        String passwordPower = serviceStaffLoginPowerDTO.getPasswordPower();

        Digester digester = DigestUtil.digester("sm3");
        String passwordPowerSM3 = digester.digestHex(passwordPower);

        ServiceStaff serviceStaff = serviceStaffMapper.getStaffByAccount(account);

        if (serviceStaff == null) {
            throw new RuntimeException("账号不存在");
        }
        if (!serviceStaff.getPasswordPower().equals(passwordPowerSM3)) {
            throw new RuntimeException("密码错误");
        }

        String token = JWTTokenUtil.genToken(serviceStaff.getId().toString(), serviceStaff.getPasswordPower(), AutoLoginOptionConstant.PowerLogin);
        return ServiceStaffLoginPowerVO.builder().token(token).build();
    }

    @Override
    public ServiceStaff getStaffById(Integer integer) {
        return serviceStaffMapper.getStaffById(integer);
    }

    @Override
    public List<StaffGetRotaVO> getAllRota() {
        List<RotaSecretKey> rotaSecretKeyList = serviceStaffMapper.getAllRota();
        List<StaffGetRotaVO> staffGetRotaVOS = new ArrayList<>();
        for (RotaSecretKey rotaSecretKey : rotaSecretKeyList) {
            String rota = rotaSecretKey.getRota();
            if (rota == null) {
                rota = "[[[], [], [], [], []], [[], [], [], [], []], [[], [], [], [], []], [[], [], [], [], []], [[], [], [], [], []]]";
            }
            StringToArrayUtil stringToArrayUtil = new StringToArrayUtil();
            String[][][] rotaArray = stringToArrayUtil.stringTo3DArray(rota);

            staffGetRotaVOS.add(StaffGetRotaVO.builder()
                    .id(rotaSecretKey.getId())
                    .adminKey(rotaSecretKey.getAdminKey())
                    .rota(rotaArray)
                    .build());
        }
        return staffGetRotaVOS;
    }

    @Override
    public List<StaffGetTableVO> getTable(String key) {
        SchoolTimetable schoolTimetableInput = new SchoolTimetable();
        if (Objects.equals(key, StaffConstant.GET_ALL_TABLE)) {
            schoolTimetableInput = null;
        } else {
            schoolTimetableInput.setKeyId(publicMapper.getRotaSecretKeyLike(key).getId());
        }
        List<SchoolTimetable> schoolTimetableList = serviceStaffMapper.getTable(schoolTimetableInput);
        List<StaffGetTableVO> staffGetTableVOS = new ArrayList<>();
        for (SchoolTimetable schoolTimetable : schoolTimetableList) {
            String table = schoolTimetable.getTable();
            if (table == null) {
                table = "[[, , , , ], [, , , , ], [, , , , ], [, , , , ], [, , , , ]]";
            }
            StringToArrayUtil stringToArrayUtil = new StringToArrayUtil();
            String[][] tableArray = stringToArrayUtil.stringTo2DArray(table);

            staffGetTableVOS.add(StaffGetTableVO.builder()
                    .id(schoolTimetable.getId())
                    .submitId(schoolTimetable.getSubmitId())
                    .name(schoolTimetable.getName())
                    .table(tableArray)
                    .build());
        }
        return staffGetTableVOS;
    }

    @Override
    public List<OcrAdminInfo> getOcrAdminInfo() {
        return serviceStaffMapper.getOcrAdminInfo();
    }

    @Override
    public void setOcrAdminInfo(OcrAdminInfo ocrAdminInfo) {
        if (ocrAdminInfo == null) {
            throw new CustomException("参数为空");
        }
        serviceStaffMapper.setOcrAdminInfo(ocrAdminInfo);
    }

    @Override
    public void addOcrAdminInfo(OcrAdminInfo ocrAdminInfo) {
        if (ocrAdminInfo == null) {
            throw new CustomException("参数为空");
        }
        String accessToken = getAccessToken(ocrAdminInfo);
        ocrAdminInfo.setAccessToken(accessToken);
        if (ocrAdminInfo.getAccessToken().isEmpty() || ocrAdminInfo.getOcrName().isEmpty() ||
        ocrAdminInfo.getSecretKey().isEmpty() || ocrAdminInfo.getApiKey().isEmpty())
            throw new CustomException("参数为空");
        serviceStaffMapper.addOcrAdminInfo(ocrAdminInfo);
    }

    @Override
    public void refreshAccessToken(int id) {
        OcrAdminInfo ocrAdminInfo = serviceStaffMapper.getOcrAdminInfoById(id);
        String accessToken = getAccessToken(ocrAdminInfo);
        serviceStaffMapper.updateAccessToken(accessToken, id);
    }

    @Override
    public String delRota(String key) {
        RotaSecretKey rotaSecretKey = publicMapper.getRotaSecretKeyLike(key);
        int count = publicMapper.deleteSchoolTimetable(rotaSecretKey.getId());
        publicMapper.deleteRotaSecretKey(rotaSecretKey.getId());


        serviceStaffMapper.delRotaSecretKey(key);
        return "密钥：" + key +"，已删除，并附带了" + count + "条课程表数据";
    }

    @Override
    public void delTable(String submitId) {
        serviceStaffMapper.delSchoolTimetable(submitId);
    }

    @Override
    public void delOcrAdminInfo(int id) {
        serviceStaffMapper.delOcrAdminInfo(id);
    }


    private String getAccessToken(OcrAdminInfo ocrAdminInfo) {
        GetOCRAccessTokenNetwork getOCRAccessTokenNetwork = new GetOCRAccessTokenNetwork();

        return getOCRAccessTokenNetwork.getOCRAccessToken(ocrAdminInfo);
    }
}
